Server And Client
Learn how to implement a network server using asyncio in Python.
We'll cover the following
Since asyncio is exceptional at handling thousands of network connections, it provides a useful framework for implementing network servers. The following example
implements a simplistic TCP server, but it is up to you to build any network server
you might like.
Note: It is possible to build an
asynciobased Web server usingaiohttp. However, it is not that useful in most cases because it will often be slower than a fast, optimized, native WSGI server likeuwsgiorgunicorn. Beacuse Python Web applications are always using WSGI, it is easy to switch out the WSGI server for a fast and asynchronous one.
Asyncio server#
Following is a simple example of a TCP server. This server listens for strings
terminated by \n and returns them in upper case.
To run the following application (server), click Run and enter the command
python asyncio-server.py.
To change the source code in the playground and run, click Run again after changing the code, then wait for the four-step process of container creation to complete. Then, click on the terminal to go back and issue the command to run the program again.
/
To implement a server, the first step is to define a class that inherits from asyncio.Protocol. It is not strictly necessary to inherit from this class, but it is a good idea to get all the basic methods defined – even if they do nothing.
The connection_made(transport) method is called as soon as a connection is
established by a client. An asyncio.BaseTransport object is passed as the argument, which represents the underlying socket and stream with the client. This object offers several methods such as get_extra_info to get more information on the client, or close method, to close the transport. The connection_lost is the other end of the connection handling code. It is called when the connection is terminated. Both connection_made and connection_lost are called once per connection.
The data_received method is called each time some data is received. It might
never be called if no data is ever received. The eof_received method might be called
once if the client sends an EOF signal.
The following figure describes the state machine and the usual workflow that asyncio.Protocol provides.
The simplest way to test the above example is to use the netcat program, available as the nc command on most versions of Unix.
In the above application, after running the server, open another terminal and enter the command nc localhost 1234 to start communication with the server. Once the connection is made, enter lowercase character strings, press enter to send, and the server will return the same string in uppercase.
Typing any text followed by \n returns it in upper case. Sending EOF by pressing Control+d closes the connection.
Asyncio client#
We have been selling asyncio as extremely fast, so it is time to prove that point.
The same asyncio.Protocol class can be used to implement a client.
To run the following application (server), clikc Run and enter command
python asyncio-server.py. Then, open another terminal, move to the relevant folder containingasyncio-client.pyusing commandcd examples/event-loops/, and then enter commandpython asyncio-client.pyto start the client.
/
The client in the above example connects to the YellEchoServer. Once connected, connection_made is called and the client sends its message via its talk method. The
server replies back with that text in uppercase, and the data_received is called. In this case, the client talks again to the server, creating an infinite loop of interaction between the two.
Note: The messages that are sent from the client to server and vice versa are not printed so you will not see anything in the terminal. However, feel free to change the code to print those messages.
Printing stats#
This is useful to test the performance of the server. By modifying some bits of the above example and adding some statistics, we can have a rough idea of the amount our server can handle.
To run the following application (server), click Run and enter command
python asyncio-server-stats.py. Then, open another terminal, and typecd examples/event-loops/. Then enter the commandpython asyncio-client.pyto start the client.
To obtain the statistics, stop the server by entering ctrl + c after some time on the terminal where the server is running.
/
In the above example, basic statistics are stored, computed, and printed at the end of the program.
While running it on my laptop with five clients at the same time, the asyncio server is able to handle more than 23,000 messages per second. Obviously, this server is not doing much work – upper-casing a string is not that impressive – but this is still a pretty decent result. Keep in mind that this server is not using any thread or any extra processes, so it is only using one single CPU.
Asyncio is a transcendent solution to write asynchronous network clients and servers. The protocol implementation is straightforward, and the ability to mix all kinds of asynchronous workload makes the framework powerful.
Using Asyncio
Naoki Inada on asyncio